#pragma once

#include "funpl.h"
#include "tokens.h"
#include "ast.h"
#include "errors.h"

namespace funpl
{

namespace parser
{

/// Parser state.
struct parser_state
{
	ast::tree *tree;
	const char *nextChar;

	const char *firstNotAcceptedBegin;
	const char *firstNotAcceptedEnd;

	struct token token;
	bool accepted;

	const char *firstChar;
	debug::error_info *pErrors;
	bool silent;

	/// Constructor.
	parser_state(ast::tree *tree, const char *firstChar, debug::error_info *pErrors)
		: nextChar(firstChar),
		firstNotAcceptedBegin(firstChar),
		firstNotAcceptedEnd(firstChar),
		tree(tree),
		accepted(true),
		firstChar(firstChar),
		pErrors(pErrors),
		silent(false) { }
};

/// Gets the current line and character position.
void line_and_pos(size_t &line, size_t &pos, const parser_state &state);

/// Gets the next token that has not yet been accepted.
parser_state& next_token(parser_state &state, bool implicitSemicolon = true);
/// Gets the next token that has not yet been accepted, ignoring any implicit semicolons.
LEAN_INLINE parser_state& next_token_cont(parser_state &state)
{
	return next_token(state, false);
}

/// Checks for the given token type, without accepting it.
bool check(parser_state &state, token_type::t type, bool implicitSemicolon = true);
/// Checks for the given token type, without accepting it. Ignores any implicit semicolons.
LEAN_INLINE bool check_cont(parser_state &state, token_type::t type)
{
	return check(state, type, false);
}

/// Accepts the current token that MUST NOT have been accepted yet.
parser_state& accept(parser_state &state);

/// Accepts tokens of the given token type.
bool accept(parser_state &state, token_type::t type, bool implicitSemicolon = true);
/// Accepts the given token type, ignoring any implicit semicolons.
LEAN_INLINE bool accept_cont(parser_state &state, token_type::t type)
{
	return accept(state, type, false);
}

/// Expects a token of the given token type.
parser_state& expect(parser_state &state, token_type::t type, bool implicitSemicolon = true);
/// Expects a token of the given token type, ignoring any implicit semicolons.
LEAN_INLINE parser_state& expect_cont(parser_state &state, token_type::t type)
{
	return expect(state, type, false);
}

/// Skips all semicolons.
parser_state& skip_semicolons(parser_state &state);

/// Checks for the given token type, without accepting it. Ignores ANY semicolons.
inline bool check_is(parser_state &state, token_type::t type)
{
	skip_semicolons(state);
	return check_cont(state, type);
}
/// Accepts the given token type, ignoring ANY implicit semicolons.
inline bool accept_is(parser_state &state, token_type::t type)
{
	skip_semicolons(state);
	return accept_cont(state, type);
}

} // namespace

} // namespace